/** 函数重载
 * 真实应用场景：有一个获取微信消息发送接口消息查找函数，根据传入的参数从数组中查找数据，如果入参为数字，就认为消息id，然后从后端数据源中找对应id的数据并返回，否则当成是类型，返回这一类型的全部消息 **/
type MessageType = 'image' | 'audio' | string; // 微信消息类型
type Message = {
  id: number;
  type: MessageType,
  sendmessage: string
};
// 这里Array<Message>也可以写成Message[]
let messages: Array<Message> = [
  {
    id: 1, type: 'image', sendmessage: '你好啊，今晚咱们一起去三里屯吧'
  },
  {
    id: 2, type: 'audio', sendmessage: '朝辞白帝彩云间，千里江陵一日还'
  },
  {
    id: 3, type: 'audio', sendmessage: '你好，我是赵无极'
  },
  {
    id: 4, type: 'image', sendmessage: '刘老根苦练舞台绝技'
  },
  {
    id: 5, type: 'image', sendmessage: '今晚看王牌对王牌吗？'
  }
]

function getMessage(id:number): Message; // 重载签名 可以有多个
function getMessage(msgType: MessageType, readCount: number): Message[]; // 重载签名
// 实现签名函数，只有实现签名才有函数体，实现签名只能有一个
function getMessage(type: any, readCount?: number):Message[] | Message | undefined {
  if (typeof type === 'number') {
    return messages.find(msg => msg.id == type);
  } else {
    const list = messages.filter(msg => msg.type === type);
    return list ? list.slice(0, readCount) : list
  }
}

getMessage(1);
getMessage('image', 2);

/** 构造器重载 
 * 计算正方形面积
 * 计算创建正方形对象，可以给构造器传递宽和高
 * 也可以给构造器传递一个包含宽和高的形状参数对象，这样需要用构造器重载**/
type type_CharParams = {// 各种图形的求面积参数
  width?:number;
  height?:number;
  radius?:number;
}
class Square {
  public width: number;
  public height: number;

  constructor(width_:number, height_:number) // 重载签名
  constructor(value:type_CharParams) // 重载签名
  constructor(paramOrWidth_: any, heght_:number=0) {
    if (typeof paramOrWidth_ === 'object') {
      this.width = paramOrWidth_.width;
      this.height = paramOrWidth_.height;
    } else {
      this.width = paramOrWidth_;
      this.height = heght_;
    }
    
  }

  public getArea():number {
    return this.height * this.width;
  }
}
let square1 = new Square(40, 50);
console.log(square1.getArea());

let chartParamsObj:type_CharParams = {
  width: 40, 
  height: 50
}
let square2 = new Square(chartParamsObj);
console.log(square2.getArea());


type Info = {
  uname: string,
  age: number
}
let myinfo:Info = { uname: 'burt', age: 18 }
const arr:Array<Info> = [{ uname: 'zhang', age: 16 }]
const arr3:Array<typeof myinfo> = [{ uname: 'zhang', age: 16 }]

// keyof： 所谓 keyof 关键字代表它接受一个对象类型作为参数，并返回该对象所有 key 值组成的联合类型。
interface IProps {
  name: string;
  age: number;
  sex: string;
}

type myKeys = keyof IProps;

// Helper function to log the keys
function logKeys<T>() {
  return (Object.keys({} as T) as Array<keyof T>).join(', ');
}

console.log(logKeys<IProps>(), 222); // Output: "name, age, sex"


interface User {
  name: string;
  age: number;
  address: string
}

type UserExcludeAddress = Exclude<keyof User, 'address' | 'age'> // "name"
// // 源码实现：
// type Exclude<T, U> = T extends U ? never : T;
type mytype = keyof any
